//
// Created by Tony on 2024/6/12.
//

#ifndef RT_CODE_CONSTANT_POOL_H
#define RT_CODE_CONSTANT_POOL_H

#include "ClassRef.h"
#include "FieldRef.h"
#include "MethodRef.h"
#include "SymRef.h"
#include <cstdint>

namespace RtCode {

enum class ConstantTag { INT64, FLT64, UTF8, STRING, CLASS_REF, FIELD_REF, METHOD_REF };

struct TaggedConstantValue {
    ConstantTag tag;

    union ConstantValue {
        int64_t int64;
        double flt64;
        uint16_t string;
    } value;

    shared_ptr<string> utf8;
    shared_ptr<ClassRef> classRef;
    shared_ptr<FieldRef> fieldRef;
    shared_ptr<MethodRef> methodRef;
};

class ConstantPool final : public enable_shared_from_this<ConstantPool> {
    vector<TaggedConstantValue> mConstantPool;
    weak_ptr<Class> mOwnerClass;

public:
    explicit ConstantPool(const shared_ptr<Class>& clazz) : mOwnerClass(clazz) {}

    uint16_t addInt64(int64_t val);
    int64_t getInt64(uint16_t index) const;

    uint16_t addFlt64(double val);
    double getFlt64(uint16_t index) const;

    uint16_t addUtf8(const string& utf8);
    const char* getUtf8(uint16_t index) const;

    uint16_t addString(const string& str);
    const char* getString(uint16_t index) const;

    uint16_t addClassRef(const string& className);
    ClassRef* getClassRef(uint16_t index) const;

    uint16_t addFieldRef(const string& className, const string& fieldName);
    FieldRef* getFieldRef(uint16_t index) const;

    uint16_t addMethodRef(const string& className, const string& methodName);
    MethodRef* getMethodRef(uint16_t index) const;

    TaggedConstantValue getConstant(uint16_t index) { return mConstantPool[index]; }

    shared_ptr<Class> getOwnerClass() const { return mOwnerClass.lock(); }

    string toString() const;
};

} // namespace RtCode

#endif // RT_CODE_CONSTANT_POOL_H
